<template>
  <div class="test-tree">
    <div class="tit">
      <div class="name">测试项目</div>
      <div v-if="testStatus !== 1" class="btns stop-btns" title="结束测试" @click="handleStop">
        <SvgIcon icon="test-stop"></SvgIcon>
      </div>
      <div class="btns" :title="statusMap[testStatus].name" @click="handleTest">
        <SvgIcon :icon="'test-' + statusMap[testStatus].icon"></SvgIcon>
      </div>
    </div>
    <el-scrollbar ref="treeScroll" v-loading="loadTree" style="height: calc(100% - 53px)">
      <el-tree ref="treeRef" :data="treeData" :highlight-current="true" :props="{ label: 'name' }" node-key="id"
        :expand-on-click-node="false" :check-on-click-leaf="false" default-expand-all
        :default-checked-keys="defaultCheckKeys" show-checkbox icon-class="el-icon-arrow-right"
        :current-node-key="current.id" @node-click="handleNodeClick" @check-change="handleCheckChange">
        <template #default="{ data }">
          <div class="custom-tree-node">
            <SvgIcon :icon="data.isCase ? 'task-node' : 'task-folder'" :size="12"></SvgIcon>
            <TooltipBox :content="data.name" :tooltipAttrs="{ placement: 'right', offset: 38 }" />
            <SvgIcon class="state-icon" :icon="'test-' + caseStatusMap[data.testState as keyof typeof caseStatusMap]"
              :size="18"></SvgIcon>
          </div>
        </template>
      </el-tree>
    </el-scrollbar>
  </div>
</template>

<script setup lang="ts">
import { ref, watch, nextTick } from "vue";
import { ElTree, ElMessage, type TreeKey, ElScrollbar } from "element-plus";
// import type { TreeParams } from "@api/test/index.d";
import { getTestCaseTrees, startTest, pauseTest, resumeTest, stopTest } from "../../api/test/index";
import type { CaseType } from "../../api/task/index.d";

const current = defineModel<Partial<CaseType>>("current", { default: () => ({}) }); // 当前选中的测试例
const testStatus = defineModel("testStatus", { default: 1 }); // 测试状态 1:初始状态 2：测试中 3：暂停中
const treeRootName = defineModel("treeRootName"); // 树根节点名称

const props = withDefaults(defineProps<{ taskId?: string }>(), { taskId: "" });

const statusMap = {
  1: { name: "开始测试", icon: "play" },
  2: { name: "暂停测试", icon: "pause" },
  3: { name: "继续测试", icon: "resume" }
} as { [key: number]: { name: string; icon: string } };
const caseStatusMap = { Testing: "testing", TestFaild: "error", TestPass: "adopt" };

const treeScroll = ref<InstanceType<typeof ElScrollbar>>(); // 测试例树滚动条
const treeRef = ref<InstanceType<typeof ElTree>>(); // 测试例树dom
const loadTree = ref(true); // 加载测试例树
const treeData = ref<CaseType[]>([]);
const defaultCheckKeys = ref<TreeKey[]>([]); // 默认勾选的节点

const selectAndScrollToNode = (nodeId: string) => {
  const node = treeRef.value?.getNode(nodeId);
  if (!node) {
    return;
  }
  const nodeEl = document.querySelector(`.is-current`) as HTMLElement;
  if (!nodeEl) return;
  // 3. 获取 el-scrollbar 容器
  const scrollbar = treeScroll.value?.wrapRef;
  if (!scrollbar) return;

  console.log("nodeEl", nodeEl);

  // 4. 计算安全滚动位置
  const containerHeight = scrollbar.clientHeight;
  const nodeHeight = nodeEl.clientHeight;
  const nodeTop = nodeEl.offsetTop;

  // 目标居中位置
  const targetScrollTop = nodeTop - (containerHeight / 2) + (nodeHeight / 2);

  // 限制滚动范围
  const maxScrollTop = scrollbar.scrollHeight - containerHeight;
  const finalScrollTop = Math.max(0, Math.min(targetScrollTop, maxScrollTop));

  // 5. 执行滚动
  scrollbar.scrollTo({ top: finalScrollTop, behavior: 'smooth' });


};

const getTreeData = async (isUpdate = false) => {
  !isUpdate && (loadTree.value = true);
  const { data } = await getTestCaseTrees({ keyword: null }, { taskId: props.taskId });
  treeData.value = data ? [{ ...data, children: handleData(data) }] : [];
  treeRootName.value = data.name || "";
  if (!isUpdate) {
    !current.value.id && findFirstChild(treeData.value);
    defaultCheckKeys.value = treeData.value.map((it) => it.id);
    loadTree.value = false;
  }
};
/**
 * @description: 测试例数据处理
 * @param {*} data
 * @return {*}
 */
const handleData = (data: any) => {
  const caseList = [...(data.testCases || []), ...(data.childCase || [])].map((it) => {
    return { ...it, isCase: true };
  });
  let children: CaseType[] = [...(data.childTree || []), ...caseList];
  if (children.length) {
    children = children.map((item) => {
      return { ...item, children: handleData(item) };
    });
  }
  return children;
};
/**
 * @description: 查找第一个子节点
 * @param {*} data
 * @return {*}
 */
const findFirstChild = (data: CaseType[]) => {
  for (let i = 0; i < data.length; i++) {
    const children = data[i].children;
    if (Array.isArray(children) && children.length) {
      findFirstChild(children);
    } else {
      current.value = data[i];
      break;
    }
  }
};

/**
 * @description: 测试状态切换
 * @return {*}
 */
const handleTest = async () => {
  const taskId = props.taskId;
  testStatus.value = testStatus.value === 3 ? 2 : testStatus.value + 1;
  // 开始测试
  if (testStatus.value === 1) {

    const halfCheckedKeys = treeRef.value?.getHalfCheckedKeys() || [];
    const checkedKeys = treeRef.value?.getCheckedKeys() || [];
    const allChks = [...halfCheckedKeys, ...checkedKeys];

    const selectCaseIds = allChks || [];
    await startTest({ selectCaseIds }, { taskId });
  } else if (testStatus.value === 2) {
    // 暂停测试
    pauseTest({}, { taskId });
  } else if (testStatus.value === 3) {
    // 继续测试
    resumeTest({}, { taskId });
  }
};

/**
 * @description: 停止测试
 * @return {*}
 */
const handleStop = async () => {
  testStatus.value = 1;
  await stopTest({}, { taskId: props.taskId });
};

/**
 * @description: 点击节点
 * @param {*} row
 * @return {*}
 */
const handleNodeClick = (row: CaseType) => {
  if (row.id === current.value.id) return;
  if (testStatus.value === 2) {
    ElMessage.warning("任务处于测试中，请暂停或结束任务后再查看");
    treeRef.value?.setCurrentKey(current.value.id);
    return;
  }
  current.value = row;
};

watch(
  () => current.value.id,
  (newVal) => {
    if (newVal) {
      if (testStatus.value === 2) {
        nextTick(() => {
          if (current.value.id) {
            selectAndScrollToNode(current.value.id);
          }
        });
      }
    }
  });

/**
 * @description: 勾选改变
 * @return {*}
 */
const handleCheckChange = () => {
  defaultCheckKeys.value = treeRef.value?.getCheckedKeys() || [];
};
/**
 * @description: 给当前节点设置数据
 * @return {*}
 */
const setTreeNodeData = () => {
  const row = treeRef.value?.getNode(current.value.id || "");
  row && (row.data.testState = current.value.testState);
};
defineExpose({ getTreeData, handleStop, setTreeNodeData });
</script>

<style lang="scss" scoped>
.test-tree {
  height: 100%;

  .tit {
    height: 52px;
    padding: 0 16px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    border-bottom: 1px solid #eaeaea;

    .name {
      font-weight: bold;
      font-size: 14px;
    }

    .btns {
      width: 26px;
      height: 26px;
      border-radius: 2px;
      background-color: #dddddd;
      margin-left: 10px;
      display: flex;
      align-items: center;
      justify-content: center;
      cursor: pointer;

      &.stop-btns {
        margin-left: auto;
        color: #fd3b3b;

        &:hover {
          color: #fd3b3b;
        }
      }

      &:hover {
        background-color: #ccc;
        color: #008efa;
        transition: all 0.3s;

        :deep(.svg-icon) {
          transform: scale(1.2);
        }
      }

      :deep(.svg-icon) {
        width: 10px;
        height: 10px;
      }
    }
  }

  :deep(.el-scrollbar) {
    .el-tree {
      --el-fill-color-blank: transparent;

      &.el-tree--highlight-current {
        .el-tree-node {
          &>.el-tree-node__content {
            &:hover {
              background: #e4e6f1;
              color: #333;
            }
          }

          &.is-current {
            &>.el-tree-node__content {
              background: #e4e6f1;
              color: #008efa;
            }
          }
        }
      }

      .el-tree-node {
        .el-tree-node__content {
          height: 32px;

          >label.el-checkbox {
            margin-right: 5px;
          }

          .custom-tree-node {
            width: calc(100% - 54px);
            display: flex;
            align-items: center;

            .svg-icon {
              margin-right: 5px;
            }
          }

          .el-checkbox__inner {
            --el-checkbox-input-border: 1px solid #ccc;
          }
        }
      }

      .el-tree-node__expand-icon {
        color: #666;
        font-weight: bold;
        margin-left: 10px;

        &.is-leaf {
          color: transparent;
          opacity: 0;
        }
      }
    }
  }
}
</style>
